<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { ModelVariableType, settledModelVariableMap } from '../../../constants/chat';
import { get_factories, set_tenant_llm, tenant_llm_name } from '../../../api/llm_service';
import { getLlmIcon } from '../../../utils';
import { API_RESULT } from '../../../constants/api';

const props = defineProps({
    isVisible: Boolean,
    modelParam: {
        type: Object,
        required: false,
        default: null
    },
})
const isAddNewModel = computed(()=> {
    return props.modelParam === null
})
const emit = defineEmits(['update:isVisible', 'onModelSet'])
const dialogVisble = computed({
  get: () => props.isVisible,
  set: (val) => {
    emit('update:isVisible', val)
  }
})

const dialogSettingTitle = computed(() => {
    return isAddNewModel.value ? "添加模型" : "设置模型"
})

const initModelForm = () => {
    return {
        llm_factory: "",
        api_key: "",
        llm: {},
        llm_setting: {
            temperature: 0.5,
            top_p: 0.5,
            frequency_penalty: 0.7,
            presence_penalty: 0.4,
        },
        fieldSwitches: {
            temperature: true,
            top_p: true,
            frequency_penalty: true,
            presence_penalty: true
        }
    }
}
const modelForm = reactive({})
Object.assign(modelForm, initModelForm())

const isDisableBtn = computed(() => {
    return modelForm.llm_factory === "" ||
        modelForm.api_key === "" ||
        Object.keys(modelForm.llm).length === 0
})

const isSelectFactory = computed(() => {
    return modelForm.llm_factory !== ""
})

const freedom = ref(ModelVariableType.Balance)
const freedom2Ch = {
    [ModelVariableType.Improvise]: "即兴创作",
    [ModelVariableType.Balance]: "平衡",
    [ModelVariableType.Precise]: "精确",
}
function onFreedomChange(selectedVal) {
    for (const [key, value] of Object.entries(settledModelVariableMap[selectedVal])) {
        modelForm.llm_setting[key] = value
    }
}

const freeParam2Str = {
    temperature: "温度",
    top_p: "Top P",
    frequency_penalty: "存在处罚",
    presence_penalty: "频率惩罚",
}

const factories_list = ref([])
onMounted(async () => {
    factories_list.value = await get_factories()
})
const llms_list = computed(() => {
    const item = factories_list.value.find(item => item.name === modelForm.llm_factory)
    // todo: 后续可能得根据模型类型做个筛选，目前支持的模型都是chat类型
    return item ? item.llms : []
})

async function onOpenDialog() {
    // 设置模型场景自由度设为"--"
    if (!isAddNewModel.value) {
        freedom.value = "--"
    } else {
        freedom.value = ModelVariableType.Balance
    }

    // 初始化表单数据
    Object.assign(modelForm, initModelForm())
    if (props.modelParam !== null) {
        modelForm.llm_factory = props.modelParam.llm_factory
        modelForm.api_key = props.modelParam.api_key
        llms_list.value.forEach((llm) => {
            if (llm.llm_name == props.modelParam.llm_name) {
                modelForm.llm = llm
            }
        })
        for (const key in modelForm.fieldSwitches) {
            if (props.modelParam.llm_setting.hasOwnProperty(key)) {
                modelForm.llm_setting[key] = props.modelParam.llm_setting[key]
            } else {
                modelForm.fieldSwitches[key] = false
            }
        }
    }
}

async function okBtnFunc() {
    dialogVisble.value = false
    const result = await set_tenant_llm(modelForm)
    if (result == API_RESULT.SUCCESS) {
        emit('onModelSet', tenant_llm_name(modelForm))
    }
}
</script>

<template>
    <el-dialog @open="onOpenDialog" v-model="dialogVisble" :title="dialogSettingTitle" width="600"
        :close-on-click-modal="false" style="padding: 20px 30px;">
        <el-form :model="modelForm" label-width="auto">
            <el-form-item label="模型提供商" required>
                <el-select v-model="modelForm.llm_factory" placeholder="" no-data-text="暂无数据">
                    <template #prefix v-if="isSelectFactory">
                        <el-image :src="getLlmIcon(`${modelForm.llm_factory.toLowerCase()}.svg`)" fit="fill"
                            style="width: 24px; height: 24px;"></el-image>
                    </template>
                    <el-option v-for="f in factories_list"
                    :key="f.name"
                    :label="f.name"
                    :value="f.name">
                    <div style="display: flex; align-items: center">
                        <el-image :src="getLlmIcon(`${f.name.toLowerCase()}.svg`)" fit="fill"
                            style="width: 24px; height: 24px;"></el-image>
                        <span style="margin-left: 8px">{{ f.name }}</span>
                    </div>
                    </el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="API Key" required>
                <el-input v-model.trim="modelForm.api_key" :disabled="!isSelectFactory"></el-input>
            </el-form-item>
            <el-form-item label="模型" required>
                <el-select v-model="modelForm.llm" :disabled="!isSelectFactory" placeholder="" no-data-text="暂无数据" value-key="llm_name">
                    <el-option v-for="l in llms_list"
                    :key="l.llm_name"
                    :label="l.llm_name"
                    :value="l">
                    </el-option>
                </el-select>
            </el-form-item>
            <el-card shadow="never">
                <template #header style="margin: 2px;">
                    <div class="card-header">
                        <el-text size="large" tag="b">自由度</el-text>
                        <span class="spacer"></span>
                        <el-select v-model="freedom" size="large" style="max-width: 160px; font-size: large;" @change="onFreedomChange">
                            <el-option v-for="item in ModelVariableType"
                                :key="item"
                                :label="freedom2Ch[item]"
                                :value="item">
                            </el-option>
                        </el-select>
                    </div>
                </template>
                <div class="card-body">
                    <div v-for="(value, key) in freeParam2Str" class="freedom-param-line">
                        <el-space wrap size="default">
                            <el-text>{{ value }}</el-text>
                            <el-switch v-model="modelForm.fieldSwitches[key]" size="small" :disabled="!isSelectFactory"/>
                            <el-slider v-model="modelForm.llm_setting[key]" :disabled="!isSelectFactory || !modelForm.fieldSwitches[key]"
                                :min="0.0" :max="1.0" :step="0.01" show-input 
                                style="width: 350px;" size="small"/>
                        </el-space>
                    </div>
                </div>
            </el-card>
        </el-form>
        <template #footer>
            <el-button v-if="!isAddNewModel" type="danger" size="default" @click="dialogVisble = false">删除</el-button>
            <el-button type="success" size="default" @click="dialogVisble = false" :disabled="isDisableBtn">测试</el-button>
            <el-button type="default" size="default" @click="dialogVisble = false">取消</el-button>
            <el-button type="primary" size="default" @click="okBtnFunc" :disabled="isDisableBtn">确定</el-button>
        </template>
    </el-dialog>
</template>

<style scoped>
.card-header {
    display: flex;
    flex-direction: row;
}

.spacer {
    flex-grow: 1;
}

:deep(.el-card__header) {
  background-color: rgb(226, 233, 247);
  padding: 10px 20px; /* 调整header内边距 */
}

.card-body {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}

.freedom-param-line {
    display: inline-flex;
    flex-direction: row;
    justify-content: flex-end;
    padding: 6px 0px;
}

.factory-select-row {
    display: inline-flex;
    flex-direction: row;
}
</style>